﻿using System;
using System.Runtime.InteropServices;

namespace UtilZ.Dotnet.Ex.Base
{
    /// <summary>
    /// A helper class for pinning a managed structure so that it is suitable for
    /// unmanaged calls. A pinned object will not be collected and will not be moved
    /// by the GC until explicitly freed.
    /// </summary>
    public sealed class PinnedObject<T> : IDisposable where T : struct
    {
        private T _managedObject;
        private GCHandle _handle;
        private IntPtr _ptr;
        private bool _disposed;

        /// <summary>
        /// 托管对象
        /// </summary>
        public T ManangedObject
        {
            get
            {
                return (T)this._handle.Target;
            }
            set
            {
                Marshal.StructureToPtr(value, this._ptr, false);
            }
        }

        /// <summary>
        /// 对象指针
        /// </summary>
        public IntPtr Ptr
        {
            get { return this._ptr; }
        }



        /// <summary>
        /// 构造函数初始化
        /// </summary>
        public PinnedObject()
        {
            this._managedObject = new T();
            this._handle = GCHandle.Alloc(this._managedObject, GCHandleType.Pinned);
            this._ptr = this._handle.AddrOfPinnedObject();
        }



        /// <summary>
        /// 析构函数
        /// </summary>
        ~PinnedObject()
        {
            Dispose();
        }

        /// <summary>
        /// Dispose
        /// </summary>
        public void Dispose()
        {
            if (this._disposed)
            {
                return;
            }

            this._handle.Free();
            this._ptr = IntPtr.Zero;
            this._disposed = true;
        }
    }
}
